diff --git a/examples/vue/package.json b/examples/vue/package.json new file mode 100644 index 00000000..6530717e --- /dev/null +++ b/examples/vue/package.json @@ -0,0 +1,13 @@ +{ + "name": "vue", + "private": true, + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [], + "author": "", + "license": "ISC" +} diff --git a/examples/vue/pages.config.js b/examples/vue/pages.config.js new file mode 100644 index 00000000..22306705 --- /dev/null +++ b/examples/vue/pages.config.js @@ -0,0 +1,5 @@ +module.exports = { + router: { + mode: 'history', + } +} diff --git a/examples/vue/src/app.js b/examples/vue/src/app.js new file mode 100644 index 00000000..ead516c9 --- /dev/null +++ b/examples/vue/src/app.js @@ -0,0 +1 @@ +export default () => {} diff --git a/examples/vue/src/pages/hello.vue b/examples/vue/src/pages/hello.vue new file mode 100644 index 00000000..f9a57721 --- /dev/null +++ b/examples/vue/src/pages/hello.vue @@ -0,0 +1,13 @@ + + + + + diff --git a/examples/vue/src/pages/home.vue b/examples/vue/src/pages/home.vue new file mode 100644 index 00000000..39a0faba --- /dev/null +++ b/examples/vue/src/pages/home.vue @@ -0,0 +1,13 @@ + + + + + diff --git a/packages/driver-pages/lib/driver.js b/packages/driver-pages/lib/driver.js index 9e80bfc7..bcbd3a5c 100644 --- a/packages/driver-pages/lib/driver.js +++ b/packages/driver-pages/lib/driver.js @@ -9,6 +9,7 @@ const exit = require( 'exit' ) const whyIsNodeRunning = require( 'why-is-node-running' ) const VirtualModulesPlugin = require( '@nut-project/webpack-virtual-modules' ) const HtmlWebpackPlugin = require( 'html-webpack-plugin' ) +const CopyPlugin = require( 'copy-webpack-plugin' ) const BundleAnalyzerPlugin = require( 'webpack-bundle-analyzer' ).BundleAnalyzerPlugin const WebpackBar = require( 'webpackbar' ) const { @@ -21,6 +22,7 @@ const { SyncHook, SyncWaterfallHook, AsyncSeriesHook, AsyncSeriesWaterfallHook } = require( 'tapable' ) const getPages = require( './get-pages' ) +const extendWebpack = require( './webpack' ) class PagesDriver { constructor( options ) { @@ -228,8 +230,12 @@ class PagesDriver { } _setupWebpack() { + const config = this.config + this._webpack = chain() + extendWebpack( this ) + // virtual modules const virtualModules = this._virtualModules = new VirtualModulesPlugin( this._getDefaultModules() @@ -267,9 +273,20 @@ class PagesDriver { .add( path.join( root, '../../' ) ) .add( path.join( root, 'node_modules' ) ) + this.webpack + .plugin( 'copy' ) + .use( CopyPlugin, [] ) + this.webpack .plugin( 'html' ) - .use( HtmlWebpackPlugin ) + .use( HtmlWebpackPlugin, [ + { + template: path.join( __dirname, './webpack/template.ejs' ), + title: config.html && config.html.title, + favicon: config.html && config.html.favicon, + excludeChunks: [], + } + ] ) this.webpack .plugin( 'webpackbar' ) @@ -284,11 +301,11 @@ class PagesDriver { async apply() { const { cli } = this - // make webpack available - this._setupWebpack() - await this.getConfig() + // make this.webpack available + this._setupWebpack() + if ( await this.getConfigFile() ) { this.verbose = this.config.verbose === true } else { @@ -560,11 +577,11 @@ class PagesDriver { } get cliOptions() { - return this._cliOptions + return this._cliOptions || {} } get config() { - return this._config + return this._config || {} } get webpack() { diff --git a/plugins/pages/microfrontends/lib/webpack/config/base.js b/packages/driver-pages/lib/webpack/base.js similarity index 99% rename from plugins/pages/microfrontends/lib/webpack/config/base.js rename to packages/driver-pages/lib/webpack/base.js index b43e0e58..870352a4 100644 --- a/plugins/pages/microfrontends/lib/webpack/config/base.js +++ b/packages/driver-pages/lib/webpack/base.js @@ -13,7 +13,6 @@ const resolveFrom = require( 'resolve-from' ) env = 'development', clean = true, browserslist: [], - transpileModules: [], include, exclude, } diff --git a/plugins/pages/microfrontends/lib/webpack/config/css.js b/packages/driver-pages/lib/webpack/css.js similarity index 100% rename from plugins/pages/microfrontends/lib/webpack/config/css.js rename to packages/driver-pages/lib/webpack/css.js diff --git a/plugins/pages/microfrontends/lib/webpack/config/dev.js b/packages/driver-pages/lib/webpack/dev.js similarity index 100% rename from plugins/pages/microfrontends/lib/webpack/config/dev.js rename to packages/driver-pages/lib/webpack/dev.js diff --git a/packages/driver-pages/lib/webpack/index.js b/packages/driver-pages/lib/webpack/index.js new file mode 100644 index 00000000..38d60b07 --- /dev/null +++ b/packages/driver-pages/lib/webpack/index.js @@ -0,0 +1,115 @@ +const path = require( 'path' ) +const base = require( './base' ) +const dev = require( './dev' ) +const prod = require( './prod' ) + +const DEFAULTS = { + browserslist: [ '>1%', 'last 4 versions', 'Firefox ESR', 'not ie < 9' ] +} + +function tryRequirePackage( context ) { + let pkg + + try { + pkg = require( path.join( context, 'package.json' ) ) + } catch ( e ) {} + + return pkg +} + +const ID = 'driver-pages:webpack' + +module.exports = function ( api ) { + api.hooks.chainWebpack.tapPromise( ID, async () => { + const pkg = tryRequirePackage( process.cwd() ) + + const browserslist = api.config.browserslist || + ( pkg && pkg.browserslist ) || + DEFAULTS.browserslist + + let transpileModules = ( + api.config.babel && api.config.babel.transpileModules + ) || [] + + // clone + transpileModules = transpileModules.slice() + + if ( api.config && api.config.plugins ) { + api.config.plugins.forEach( plugin => { + const pkg = tryRequirePackage( plugin.context ) + + if ( pkg ) { + transpileModules.push( pkg.name ) + } else { + transpileModules.push( function ( filepath ) { + return filepath.includes( plugin.context ) + } ) + } + } ) + } + + const exclude = [ + /\.nut\/pages\.js/, + /\.nut\/routes\.js/, + /\.nut\/route-components\//, + ] + + const includeCaches = {} + + // from egoist/poi + function include( filepath ) { + filepath = filepath.replace( /\\/g, '/' ) + + // use cache + if ( typeof includeCaches[ filepath ] === 'boolean' ) { + return includeCaches[ filepath ] + } + + if ( !filepath.includes( 'node_modules' ) ) { + includeCaches[ filepath ] = true + return true + } + + if ( transpileModules ) { + const shouldTranspile = transpileModules.some( m => { + if ( typeof m === 'string' ) { + return filepath.includes( `/node_modules/${ m }/` ) || + filepath.includes( `/node_modules/_${ m.replace( /\//g, '_' ) }` ) + } + + if ( typeof m === 'function' ) { + return m( filepath ) + } + + if ( m && m.test ) { + return m.test( filepath ) + } + + return false + } ) + + includeCaches[ filepath ] = shouldTranspile + return shouldTranspile + } + + includeCaches[ filepath ] = false + return false + } + + const options = { + browserslist, + include, + exclude, + clean: api.config.output && api.config.output.clean === true, + publicPath: api.config.output && api.config.output.publicPath, + } + + base( api.webpack, options ) + + if ( api.env === 'production' ) { + prod( api.webpack, options ) + } else { + dev( api.webpack, options ) + } + } ) +} diff --git a/plugins/pages/microfrontends/lib/webpack/config/prod.js b/packages/driver-pages/lib/webpack/prod.js similarity index 100% rename from plugins/pages/microfrontends/lib/webpack/config/prod.js rename to packages/driver-pages/lib/webpack/prod.js diff --git a/packages/driver-pages/lib/webpack/template.ejs b/packages/driver-pages/lib/webpack/template.ejs new file mode 100644 index 00000000..5ce154c3 --- /dev/null +++ b/packages/driver-pages/lib/webpack/template.ejs @@ -0,0 +1,11 @@ + + + + <%= htmlWebpackPlugin.options.title %> + + + + + diff --git a/plugins/pages/microfrontends/lib/webpack/config/tsconfig.json b/packages/driver-pages/lib/webpack/tsconfig.json similarity index 100% rename from plugins/pages/microfrontends/lib/webpack/config/tsconfig.json rename to packages/driver-pages/lib/webpack/tsconfig.json diff --git a/packages/driver-pages/package.json b/packages/driver-pages/package.json index c4eeab62..640b2de4 100644 --- a/packages/driver-pages/package.json +++ b/packages/driver-pages/package.json @@ -1,60 +1,101 @@ { "name": "@nut-project/driver-pages", "version": "1.0.0-alpha.3", - "publishConfig": { - "access": "public" - }, "description": "A framework born for micro frontends", "keywords": [ - "microfrontends", - "micro", - "frontend", "architecture", - "spa", "cli", - "static site generator", - "hmr" - ], - "main": "lib/index.js", - "files": [ - "bin", - "lib", - "yarn.lock", - "README.md" + "frontend", + "hmr", + "micro", + "microfrontends", + "spa", + "static site generator" ], - "engines": { - "node": ">=8.9.0" - }, - "repository": "https://github.com/nut-project/nut/tree/master/packages/gatherer", "homepage": "http://nut.js.org", "bugs": { "url": "https://github.com/nut-project/nut/issues/new/choose" }, - "scripts": { - "prepublishOnly": "cp ../../README.md ./README.md" - }, + "repository": "https://github.com/nut-project/nut/tree/master/packages/gatherer", + "license": "MIT", "author": { "name": "fengzilong", "email": "fengzilong1992@gmail.com", "url": "https://github.com/fengzilong" }, - "license": "MIT", + "files": [ + "bin", + "lib", + "yarn.lock", + "README.md" + ], + "main": "lib/index.js", + "scripts": { + "prepublishOnly": "cp ../../README.md ./README.md" + }, "dependencies": { + "@babel/core": "^7.6.2", + "@babel/plugin-syntax-dynamic-import": "^7.2.0", + "@babel/plugin-transform-runtime": "^7.6.2", + "@babel/preset-env": "^7.6.2", + "@babel/preset-react": "^7.0.0", + "@babel/runtime": "^7.6.2", "@nut-project/dev-utils": "^1.0.0-alpha.2", + "@nut-project/mini-css-extract": "^1.0.0-alpha.2", "@nut-project/webpack": "^1.0.0-alpha.2", "@nut-project/webpack-virtual-modules": "^1.0.0-alpha.2", + "@vue/babel-helper-vue-jsx-merge-props": "^1.0.0", + "@vue/babel-preset-jsx": "^1.1.0", + "autoprefixer": "^9.6.1", + "babel-loader": "^8.0.6", + "cache-loader": "^4.1.0", + "case-sensitive-paths-webpack-plugin": "^2.2.0", "chokidar": "^3.1.0", + "clean-webpack-plugin": "^3.0.0", + "copy-webpack-plugin": "^5.0.4", + "css-loader": "^3.2.0", "exit": "^0.1.2", + "file-loader": "^4.2.0", + "fork-ts-checker-webpack-plugin": "^1.5.0", + "friendly-errors-webpack-plugin": "^1.7.0", "globby": "^10.0.1", "html-webpack-plugin": "^3.2.0", "import-fresh": "^3.1.0", + "less": "^3.10.3", + "less-loader": "^5.0.0", + "optimize-css-assets-webpack-plugin": "^5.0.3", + "postcss": "^7.0.21", + "postcss-loader": "^3.0.0", "pretty-bytes": "^5.2.0", + "pug": "^2.0.4", + "pug-plain-loader": "^1.0.0", + "raw-loader": "^3.1.0", "readline": "^1.3.0", "resolve-from": "^5.0.0", + "sass": "^1.23.3", + "sass-loader": "^8.0.0", + "style-loader": "^1.0.0", + "stylus": "^0.54.7", + "stylus-loader": "^3.0.2", "tapable": "^1.1.3", + "terser-webpack-plugin": "^2.1.0", + "thread-loader": "^2.1.3", "tildify": "^2.0.0", + "ts-loader": "^6.1.2", + "tslint": "^5.18.0", + "typescript": "^3.6.3", + "url-loader": "^2.1.0", + "vue": "^2.6.10", + "vue-loader": "^15.7.2", + "vue-template-compiler": "^2.6.10", "webpack-bundle-analyzer": "^3.6.0", "webpackbar": "^4.0.0", "why-is-node-running": "^2.1.0" + }, + "engines": { + "node": ">=8.9.0" + }, + "publishConfig": { + "access": "public" } } diff --git a/packages/webpack-presets/.gitkeep b/packages/webpack-presets/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/plugins/pages/microfrontends/lib/index.js b/plugins/pages/microfrontends/lib/index.js index c1464608..5fcd0106 100644 --- a/plugins/pages/microfrontends/lib/index.js +++ b/plugins/pages/microfrontends/lib/index.js @@ -1,6 +1,5 @@ /* eslint-disable indent */ -const fs = require( 'fs' ) const path = require( 'path' ) const boxen = require( 'boxen' ) const address = require( 'address' ) @@ -8,8 +7,6 @@ const table = require( 'text-table' ) const stringWidth = require( 'string-width' ) const prettyBytes = require( 'pretty-bytes' ) const slugify = require( '@sindresorhus/slugify' ) -const HtmlWebpackPlugin = require( 'html-webpack-plugin' ) -const CopyPlugin = require( 'copy-webpack-plugin' ) const StatsWriterPlugin = require( 'webpack-stats-plugin' ).StatsWriterPlugin const generateModules = require( './generate-modules' ) const { getUniqueApplicationId } = require( './utils' ) @@ -87,8 +84,6 @@ module.exports = { // core plugins is ahead of all user plugins // so we should use beforeRun hook to get all runtime modules api.hooks.beforeRun.tapPromise( ID, async () => { - extend( api.webpack, api.config, api.env ) - await this.base() if ( api.env === 'production' ) { @@ -110,24 +105,16 @@ module.exports = { async base() { const { webpack: config, config: nutConfig } = this.api + extend( config, nutConfig ) + config .resolve .alias .set( '#runtime', path.join( dirs.runtime, 'entries/default-runtime.js' ) ) - let templatePath - - if ( nutConfig.html && nutConfig.html.template ) { - templatePath = nutConfig.html && nutConfig.html.template - } else if ( fs.existsSync( path.resolve( dirs.project, 'src/index.ejs' ) ) ) { - templatePath = path.resolve( dirs.project, 'src/index.ejs' ) - } else { - templatePath = path.join( dirs.runtime, 'template.ejs' ) - } - config - .plugin( 'copy' ) - .use( CopyPlugin, [ + .plugin( 'copy-public' ) + .use( config.plugin( 'copy' ).get( 'plugin' ), [ [ { from: { @@ -143,14 +130,15 @@ module.exports = { } ] ) .end() - .plugin( 'html' ) - .use( HtmlWebpackPlugin, [ + .plugin( 'html' ) // TODO: need rebuild after change html + .tap( ( [ options ] ) => [ { - ...( nutConfig.html || {} ), - template: templatePath, - title: ( nutConfig.html && nutConfig.html.title ) || nutConfig.zh || nutConfig.en, - favicon: ( nutConfig.html && nutConfig.html.favicon ) || path.join( dirs.runtime, 'favicon.png' ), - excludeChunks: [ 'child' ], + ...options, + template: ( nutConfig.html && nutConfig.html.template ) || + path.join( __dirname, './webpack/template.ejs' ), + excludeChunks: [ ...( options.excludeChunks || [] ), 'child' ], + title: options.title || nutConfig.zh || nutConfig.en, + favicon: options.favicon || path.join( __dirname, './webpack/favicon.png' ) } ] ) .end() diff --git a/plugins/pages/microfrontends/lib/utils/dirs.js b/plugins/pages/microfrontends/lib/utils/dirs.js index a9fa33ee..33084b7e 100644 --- a/plugins/pages/microfrontends/lib/utils/dirs.js +++ b/plugins/pages/microfrontends/lib/utils/dirs.js @@ -1,6 +1,6 @@ const path = require( 'path' ) module.exports = { - driver: path.join( __dirname, '../../' ), + root: path.join( __dirname, '../../' ), project: process.cwd(), } diff --git a/plugins/pages/microfrontends/files/favicon.ico b/plugins/pages/microfrontends/lib/webpack/favicon.ico similarity index 100% rename from plugins/pages/microfrontends/files/favicon.ico rename to plugins/pages/microfrontends/lib/webpack/favicon.ico diff --git a/plugins/pages/microfrontends/files/favicon.png b/plugins/pages/microfrontends/lib/webpack/favicon.png similarity index 100% rename from plugins/pages/microfrontends/files/favicon.png rename to plugins/pages/microfrontends/lib/webpack/favicon.png diff --git a/plugins/pages/microfrontends/lib/webpack/index.js b/plugins/pages/microfrontends/lib/webpack/index.js index 00234032..d0f7f1d5 100644 --- a/plugins/pages/microfrontends/lib/webpack/index.js +++ b/plugins/pages/microfrontends/lib/webpack/index.js @@ -4,103 +4,8 @@ const path = require( 'path' ) const resolveFrom = require( 'resolve-from' ) const dirs = require( '../utils/dirs' ) const getBabelOptions = require( './get-babel-options' ) -const base = require( './config/base' ) -const dev = require( './config/dev' ) -const prod = require( './config/prod' ) - -let pkg = {} -try { - pkg = require( dirs.project + '/package.json' ) -} catch ( e ) {} - -module.exports = function extend( config, nutConfig = {}, env ) { - const browserslist = pkg.browserslist || - [ '>1%', 'last 4 versions', 'Firefox ESR', 'not ie < 9' ] - - const transpileModules = ( - nutConfig.babel && nutConfig.babel.transpileModules - ) || [] - const internalTranspileModules = [ - 'unfancy-router/src', - `${ pkg.name }/lib/runtime/files`, - /@nut-plugins/i, - 'debug', // from docsearch.js -> algoliasearch -> debug - ] - - if ( nutConfig.plugins ) { - const plugins = nutConfig.plugins - Object.keys( plugins ).forEach( name => { - if ( plugins[ name ].package ) { - internalTranspileModules.push( plugins[ name ].package ) - } - } ) - } - - const allTranspileModules = [] - .concat( transpileModules ) - .concat( internalTranspileModules ) - - const exclude = [ - /\.nut\/pages\.js/, - /\.nut\/routes\.js/, - /\.nut\/route-components\//, - ] - - const jsIncludeCaches = {} - - // from egoist/poi - function include( filepath ) { - filepath = filepath.replace( /\\/g, '/' ) - - // use cache - if ( typeof jsIncludeCaches[ filepath ] === 'boolean' ) { - return jsIncludeCaches[ filepath ] - } - - if ( !filepath.includes( 'node_modules' ) ) { - jsIncludeCaches[ filepath ] = true - return true - } - - if ( allTranspileModules ) { - const shouldTranspile = allTranspileModules.some( m => { - if ( typeof m === 'string' ) { - return filepath.includes( `/node_modules/${ m }/` ) || - filepath.includes( `/node_modules/_${ m.replace( /\//g, '_' ) }` ) - } - - if ( m && m.test ) { - return m.test( filepath ) - } - - return false - } ) - - jsIncludeCaches[ filepath ] = shouldTranspile - return shouldTranspile - } - - jsIncludeCaches[ filepath ] = false - return false - } - - const options = { - browserslist, - include, - exclude, - clean: nutConfig.output && nutConfig.output.clean === true, - publicPath: nutConfig.output && nutConfig.output.publicPath, - transpileModules: allTranspileModules, - } - - base( config, options ) - - if ( env === 'production' ) { - prod( config, options ) - } else { - dev( config, options ) - } +module.exports = function extend( config, nutConfig = {} ) { let vuePkgPath = resolveFrom.silent( process.cwd(), 'vue/package.json' ) if ( !vuePkgPath ) { vuePkgPath = resolveFrom.silent( __dirname, 'vue/package.json' ) @@ -137,14 +42,14 @@ module.exports = function extend( config, nutConfig = {}, env ) { .set( 'vue$', vuePath ) .end() .modules - .add( path.join( dirs.driver, '../../' ) ) - .add( path.join( dirs.driver, 'node_modules' ) ) + .add( path.join( dirs.root, '../../' ) ) + .add( path.join( dirs.root, 'node_modules' ) ) .end() .end() .resolveLoader .modules - .add( path.join( dirs.driver, '../../' ) ) - .add( path.join( dirs.driver, 'node_modules' ) ) + .add( path.join( dirs.root, '../../' ) ) + .add( path.join( dirs.root, 'node_modules' ) ) .end() const babelOptions = getBabelOptions() diff --git a/plugins/pages/microfrontends/files/template.ejs b/plugins/pages/microfrontends/lib/webpack/template.ejs similarity index 100% rename from plugins/pages/microfrontends/files/template.ejs rename to plugins/pages/microfrontends/lib/webpack/template.ejs diff --git a/plugins/pages/microfrontends/package.json b/plugins/pages/microfrontends/package.json index 3630cf03..1a44b12e 100644 --- a/plugins/pages/microfrontends/package.json +++ b/plugins/pages/microfrontends/package.json @@ -31,83 +31,39 @@ }, "license": "MIT", "dependencies": { - "@babel/core": "^7.6.2", - "@babel/plugin-syntax-dynamic-import": "^7.2.0", - "@babel/plugin-transform-runtime": "^7.6.2", - "@babel/preset-env": "^7.6.2", - "@babel/preset-react": "^7.0.0", - "@babel/runtime": "^7.6.2", "@mapbox/rehype-prism": "^0.3.1", "@mdx-js/mdx": "^1.0.21", "@mdx-js/vue": "1.0.20", "@nut-project/dev-utils": "^1.0.0-alpha.2", - "@nut-project/mini-css-extract": "^1.0.0-alpha.2", - "@nut-project/webpack": "^1.0.0-alpha.2", "@sindresorhus/slugify": "^0.9.1", - "@vue/babel-helper-vue-jsx-merge-props": "^1.0.0", - "@vue/babel-preset-jsx": "^1.1.0", "address": "^1.1.2", - "autoprefixer": "^9.6.1", "axios": "^0.19.0", - "babel-loader": "^8.0.6", "boxen": "^4.1.0", - "cache-loader": "^4.1.0", - "case-sensitive-paths-webpack-plugin": "^2.2.0", - "clean-webpack-plugin": "^3.0.0", - "copy-webpack-plugin": "^5.0.4", - "css-loader": "^3.2.0", "deepmerge": "^4.0.0", "docsearch.js": "^2.6.3", - "file-loader": "^4.2.0", - "fork-ts-checker-webpack-plugin": "^1.5.0", - "friendly-errors-webpack-plugin": "^1.7.0", "front-matter": "^3.0.1", "fs-extra": "^8.1.0", "hash-sum": "^2.0.0", "headroom.js": "^0.9.4", - "html-webpack-plugin": "^3.2.0", - "less": "^3.10.3", - "less-loader": "^5.0.0", "marked": "^0.6.1", "mdast-util-toc": "^4.2.0", - "mini-css-extract-plugin": "^0.8.0", "nprogress": "^0.2.0", - "optimize-css-assets-webpack-plugin": "^5.0.3", "popper.js": "^1.15.0", - "postcss-loader": "^3.0.0", "pretty-bytes": "^5.2.0", "prism-themes": "^1.1.0", "prismjs": "^1.16.0", - "pug": "^2.0.4", - "pug-plain-loader": "^1.0.0", "query-string": "5", "quicklink": "^1.0.0", - "raw-loader": "^3.1.0", "react": "^16.8.6", "react-dom": "^16.8.6", "regularjs": "^0.6.2", "rehype-slug": "^2.0.3", "resolve-from": "^5.0.0", - "sao": "^1.6.1", - "sass": "^1.22.12", - "sass-loader": "^8.0.0", "string-width": "^4.1.0", - "style-loader": "^1.0.0", - "stylus": "^0.54.7", - "stylus-loader": "^3.0.2", - "terser-webpack-plugin": "^2.1.0", "text-table": "^0.2.0", - "thread-loader": "^2.1.3", "tippy.js": "^4.2.1", - "ts-loader": "^6.1.2", - "tslint": "^5.18.0", - "typescript": "^3.6.3", "unfancy-router": "0.1.10", "unist-util-visit": "^1.4.1", - "url-loader": "^2.1.0", - "vue": "^2.6.10", - "vue-loader": "^15.7.1", - "vue-template-compiler": "^2.6.10", "webpack-stats-plugin": "^0.3.0", "ws": "^7.1.2" } diff --git a/plugins/pages/runtime-vue/files/App.vue b/plugins/pages/runtime-vue/files/App.vue new file mode 100644 index 00000000..943399a2 --- /dev/null +++ b/plugins/pages/runtime-vue/files/App.vue @@ -0,0 +1,11 @@ + + + diff --git a/plugins/pages/runtime-vue/files/app.js b/plugins/pages/runtime-vue/files/app.js new file mode 100644 index 00000000..d53d36c6 --- /dev/null +++ b/plugins/pages/runtime-vue/files/app.js @@ -0,0 +1,27 @@ +import Vue from 'vue' +import createRouter from './router' +import App from './App.vue' +import context from '#context' + +const mode = ( context.app.router && context.app.router.mode ) || 'history' +const routes = [ + { path: '/', component: () => import( /* webpackChunkName: "home" */ '@/pages/home.vue' ) }, + { path: '/hello', component: () => import( /* webpackChunkName: "hello" */ '@/pages/hello.vue' ) }, +] + +export default () => { + const router = createRouter( { + mode, + routes, + } ) + + const app = new Vue( { + router, + render: h => h( App ) + } ) + + return { + app, + router, + } +} diff --git a/plugins/pages/runtime-vue/files/entry-client.js b/plugins/pages/runtime-vue/files/entry-client.js new file mode 100644 index 00000000..e96b0348 --- /dev/null +++ b/plugins/pages/runtime-vue/files/entry-client.js @@ -0,0 +1,9 @@ +import createApp from './app' + +export default () => { + const { app, router } = createApp() + + router.onReady( () => { + app.$mount( '#app' ) + } ) +} diff --git a/plugins/pages/runtime-vue/files/entry-server.js b/plugins/pages/runtime-vue/files/entry-server.js new file mode 100644 index 00000000..a31affa0 --- /dev/null +++ b/plugins/pages/runtime-vue/files/entry-server.js @@ -0,0 +1,18 @@ +import createApp from './app' + +export default context => { + return new Promise( ( resolve, reject ) => { + const { app, router } = createApp() + + router.push( context.url ) + + router.onReady( () => { + const matchedComponents = router.getMatchedComponents() + if ( !matchedComponents.length ) { + return reject( { code: 404 } ) + } + + resolve( app ) + }, reject ) + } ) +} diff --git a/plugins/pages/runtime-vue/files/router.js b/plugins/pages/runtime-vue/files/router.js new file mode 100644 index 00000000..c7f761b4 --- /dev/null +++ b/plugins/pages/runtime-vue/files/router.js @@ -0,0 +1,11 @@ +import Vue from 'vue' +import Router from 'vue-router' + +Vue.use( Router ) + +export function createRouter( { mode, routes } = {} ) { + return new Router( { + mode, + routes, + } ) +} diff --git a/plugins/pages/runtime-vue/lib/index.js b/plugins/pages/runtime-vue/lib/index.js new file mode 100644 index 00000000..d339a388 --- /dev/null +++ b/plugins/pages/runtime-vue/lib/index.js @@ -0,0 +1,18 @@ +const path = require( 'path' ) + +const ID = 'runtime-vue' + +module.exports = { + name: ID, + + core: true, + + async apply( api ) { + api.hooks.chainWebpack.tapPromise( ID, async config => { + config + .resolve + .alias + .set( '@', path.join( process.cwd(), 'src' ) ) + } ) + } +} diff --git a/plugins/pages/runtime-vue/package.json b/plugins/pages/runtime-vue/package.json new file mode 100644 index 00000000..4648b440 --- /dev/null +++ b/plugins/pages/runtime-vue/package.json @@ -0,0 +1,36 @@ +{ + "name": "@nut-plugins/pages-runtime-vue", + "version": "1.0.0-alpha.3", + "publishConfig": { + "access": "public" + }, + "description": "runtime-vue", + "keywords": [ + "nut", + "pages", + "plugin" + ], + "main": "lib/index.js", + "files": [ + "lib", + "files" + ], + "engines": { + "node": ">=8.9.0" + }, + "repository": "https://github.com/nut-project/nut/tree/master/plugins/pages/runtime-vue", + "homepage": "http://nut.js.org", + "bugs": { + "url": "https://github.com/nut-project/nut/issues/new/choose" + }, + "scripts": {}, + "author": { + "name": "fengzilong", + "email": "fengzilong1992@gmail.com", + "url": "https://github.com/fengzilong" + }, + "license": "MIT", + "dependencies": { + + } +} diff --git a/website/pages.config.js b/website/pages.config.js index b3fdee08..d5dae073 100644 --- a/website/pages.config.js +++ b/website/pages.config.js @@ -30,6 +30,7 @@ const config = { zh: 'nut project', html: { title: 'NUT 文档', + template: path.join( __dirname, 'src/index.ejs' ), }, logo: '/logo.png', theme: 'ocean', diff --git a/yarn.lock b/yarn.lock index 66bf4f70..c12902b4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8433,16 +8433,6 @@ min-document@^2.19.0: dependencies: dom-walk "^0.1.0" -mini-css-extract-plugin@^0.8.0: - version "0.8.0" - resolved "https://registry.yarnpkg.com/mini-css-extract-plugin/-/mini-css-extract-plugin-0.8.0.tgz#81d41ec4fe58c713a96ad7c723cdb2d0bd4d70e1" - integrity sha512-MNpRGbNA52q6U92i0qbVpQNsgk7LExy41MdAlG84FeytfDOtRIf/mCHdEgG8rpTKOaNKiqUnZdlptF469hxqOw== - dependencies: - loader-utils "^1.1.0" - normalize-url "1.9.1" - schema-utils "^1.0.0" - webpack-sources "^1.1.0" - minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7" @@ -8850,7 +8840,7 @@ normalize-range@^0.1.2: resolved "https://registry.yarnpkg.com/normalize-range/-/normalize-range-0.1.2.tgz#2d10c06bdfd312ea9777695a4d28439456b75942" integrity sha1-LRDAa9/TEuqXd2laTShDlFa3WUI= -normalize-url@1.9.1, normalize-url@^1.0.0: +normalize-url@^1.0.0: version "1.9.1" resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-1.9.1.tgz#2cc0d66b31ea23036458436e3620d85954c66c3c" integrity sha1-LMDWazHqIwNkWENuNiDYWVTGbDw= @@ -10028,6 +10018,15 @@ postcss@^7.0.0, postcss@^7.0.1, postcss@^7.0.14, postcss@^7.0.16, postcss@^7.0.1 source-map "^0.6.1" supports-color "^6.1.0" +postcss@^7.0.21: + version "7.0.21" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.21.tgz#06bb07824c19c2021c5d056d5b10c35b989f7e17" + integrity sha512-uIFtJElxJo29QC753JzhidoAhvp/e/Exezkdhfmt8AymWT6/5B7W1WmponYWkHk2eg6sONyTch0A3nkMPun3SQ== + dependencies: + chalk "^2.4.2" + source-map "^0.6.1" + supports-color "^6.1.0" + prelude-ls@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" @@ -11044,7 +11043,7 @@ safe-regex@^1.1.0: resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== -sao@^1.6.1, sao@^1.7.0: +sao@^1.7.0: version "1.7.0" resolved "https://registry.yarnpkg.com/sao/-/sao-1.7.0.tgz#19b61f95c62b3f71550c8d8911c88bb7d9ef49df" integrity sha512-5ZJ6C1odSSqdFtgh/gNfwwmTgCTOnbXWQkyAyLv//9uSTsaGVyeVrNa0rS/o32pVSKlmyPg5C10KoGT3+rY1rw== @@ -11082,10 +11081,10 @@ sass-loader@^8.0.0: schema-utils "^2.1.0" semver "^6.3.0" -sass@^1.22.12: - version "1.23.0" - resolved "https://registry.yarnpkg.com/sass/-/sass-1.23.0.tgz#bd526ff40dbc5d09a4ed69e2cffa849749977710" - integrity sha512-W4HT8+WE31Rzk3EPQC++CXjD5O+lOxgYBIB8Ohvt7/zeE2UzYW+TOczDrRU3KcEy3+xwXXbmDsOZFkoqgD4TKw== +sass@^1.23.3: + version "1.23.3" + resolved "https://registry.yarnpkg.com/sass/-/sass-1.23.3.tgz#f07503b9e8d2bcf06ef69e8beea5d085589b1620" + integrity sha512-1DKRZxJMOh4Bme16AbWTyYeJAjTlrvw2+fWshHHaepeJfGq2soFZTnt0YhWit+bohtDu4LdyPoEj6VFD4APHog== dependencies: chokidar ">=2.0.0 <4.0.0" @@ -12898,10 +12897,10 @@ vue-hot-reload-api@^2.3.0: resolved "https://registry.yarnpkg.com/vue-hot-reload-api/-/vue-hot-reload-api-2.3.4.tgz#532955cc1eb208a3d990b3a9f9a70574657e08f2" integrity sha512-BXq3jwIagosjgNVae6tkHzzIk6a8MHFtzAdwhnV5VlvPTFxDCvIttgSiHWjdGoTJvXtmRu5HacExfdarRcFhog== -vue-loader@^15.7.1: - version "15.7.1" - resolved "https://registry.yarnpkg.com/vue-loader/-/vue-loader-15.7.1.tgz#6ccacd4122aa80f69baaac08ff295a62e3aefcfd" - integrity sha512-fwIKtA23Pl/rqfYP5TSGK7gkEuLhoTvRYW+TU7ER3q9GpNLt/PjG5NLv3XHRDiTg7OPM1JcckBgds+VnAc+HbA== +vue-loader@^15.7.2: + version "15.7.2" + resolved "https://registry.yarnpkg.com/vue-loader/-/vue-loader-15.7.2.tgz#cc89e2716df87f70fe656c9da9d7f8bec06c73d6" + integrity sha512-H/P9xt/nkocyu4hZKg5TzPqyCT1oKOaCSk9zs0JCbJuy0Q8KtR0bjJpnT/5R5x/Ckd1GFkkLQnQ1C4x6xXeLZg== dependencies: "@vue/component-compiler-utils" "^3.0.0" hash-sum "^1.0.2"