UNPKG

neutrino-preset-laima-web

Version:

Neutrino preset for laima project

295 lines (283 loc) 8.76 kB
const { join, resolve } = require('path') const merge = require('deepmerge') const git = require('git-rev-sync') const LodashModuleReplacementPlugin = require('lodash-webpack-plugin') const { optimize } = require('webpack') const htmlLoader = require('@neutrinojs/html-loader') const styleLoader = require('@neutrinojs/style-loader') const fontLoader = require('@neutrinojs/font-loader') const imageLoader = require('@neutrinojs/image-loader') const compileLoader = require('@neutrinojs/compile-loader') const env = require('@neutrinojs/env') const hot = require('@neutrinojs/hot') const htmlTemplate = require('@neutrinojs/html-template') const copy = require('@neutrinojs/copy') const clean = require('@neutrinojs/clean') const minify = require('@neutrinojs/minify') const loaderMerge = require('@neutrinojs/loader-merge') const devServer = require('@neutrinojs/dev-server') const pwa = require('@neutrinojs/pwa') const compression = require('neutrino-middleware-compression') const bundleanalyzer = require('neutrino-middleware-bundleanalyzer') const caseSensitivePaths = require('neutrino-middleware-case-sensitive-paths') const browserSync = require('neutrino-middleware-browser-sync') const MODULES = join(__dirname, 'node_modules') module.exports = (neutrino, opts = {}) => { const publicPath = './' const options = merge( { publicPath, env: [], hot: true, hotEntries: [], html: { title: 'Laima Web App', template: resolve(__dirname, 'template.ejs'), git: git.short(), rev: new Date().toISOString(), minify: { preserveLineBreaks: false } }, polyfills: { async: true }, devServer: { port: 3100, hot: opts.hot !== false, publicPath: resolve('/', publicPath) }, style: { hot: opts.hot !== false, extract: (opts.style && opts.style.extract) || (process.env.NODE_ENV === 'production' && {}), css: { localIdentName: '[name]__[local]--[hash:base64:5]' }, modulesTest: /\.css$/, loaders: [ { loader: require.resolve('postcss-loader'), useId: 'postcss', options: { config: { path: join(process.cwd(), 'postcss.config.js') } } } ] }, clean: opts.clean !== false && { paths: [neutrino.options.output] }, minify: { babel: {}, style: {}, image: false }, babel: {}, targets: {}, font: {}, image: {} }, opts ) if (typeof options.devServer.proxy === 'string') { options.devServer.proxy = { '**': { target: options.devServer.proxy, changeOrigin: true } } } if (!options.targets.node && !options.targets.browsers) { options.targets.browsers = [ 'last 2 Chrome versions', 'last 2 Firefox versions', 'last 2 Edge versions', 'last 2 Opera versions', 'last 2 Safari versions', 'last 2 iOS versions' ] } Object.assign(options, { minify: { babel: options.minify.babel === true ? {} : options.minify.babel, style: options.minify.style === true ? {} : options.minify.style, image: options.minify.image === true ? {} : options.minify.image }, babel: compileLoader.merge( { plugins: [ ...(options.polyfills.async ? [[require.resolve('fast-async'), { spec: true }]] : []), require.resolve('babel-plugin-syntax-dynamic-import'), require.resolve('babel-plugin-lodash') ], presets: [ [ require.resolve('babel-preset-env'), { debug: neutrino.options.debug, modules: false, useBuiltIns: true, exclude: options.polyfills.async ? ['transform-regenerator', 'transform-async-to-generator'] : [], targets: options.targets } ] ] }, options.babel ) }) const staticDir = join(neutrino.options.source, 'static') neutrino.use(env, options.env) neutrino.use(htmlLoader) neutrino.use(htmlTemplate, options.html) neutrino.use(compileLoader, { include: [neutrino.options.source, neutrino.options.tests], exclude: [staticDir], babel: options.babel }) neutrino.use(bundleanalyzer) neutrino.use(caseSensitivePaths) neutrino.use(copy, { patterns: [ { context: staticDir, from: '**/*', to: '.', transform: (content, path) => { if (process.env.NODE_ENV !== 'production') { return content } if (path.match(/\.json$/)) { return JSON.stringify(JSON.parse(content)) } return content } } ] }) Object.keys(neutrino.options.mains).forEach(key => { neutrino.config .entry(key) .add(neutrino.options.mains[key]) .when(options.html, () => { neutrino.use( htmlTemplate, merge( { pluginId: `html-${key}`, filename: `${key}.html` }, options.html ) ) }) }) neutrino.config .when(options.style, () => neutrino.use(styleLoader, options.style)) .when(options.font, () => neutrino.use(fontLoader, options.font)) .when(options.image, () => neutrino.use(imageLoader, options.image)) .target('web') .context(neutrino.options.root) .output.path(neutrino.options.output) .publicPath(options.publicPath) .filename('[name].js') .chunkFilename('[name].[chunkhash].js') .end() .resolve.modules.add('node_modules') .add(neutrino.options.node_modules) .add(MODULES) .end() .extensions.merge(neutrino.options.extensions.concat('json').map(ext => `.${ext}`)) .end() .end() .resolveLoader.modules.add(neutrino.options.node_modules) .add(MODULES) .end() .end() .node.set('Buffer', false) .set('fs', 'empty') .set('tls', 'empty') .end() .plugin('lodash') .use(LodashModuleReplacementPlugin) .end() .module.rule('worker') .test(neutrino.regexFromExtensions(neutrino.options.extensions.map(ext => `worker.${ext}`))) .use('worker') .loader(require.resolve('worker-loader')) .end() .end() .end() .when(neutrino.config.module.rules.has('lint'), () => { neutrino.use(loaderMerge('lint', 'eslint'), { envs: ['browser', 'commonjs'] }) }) .when(process.env.NODE_ENV === 'development', config => config.devtool('cheap-module-eval-source-map')) .when(neutrino.options.command === 'start', config => { config.when(options.hot, () => { neutrino.use(hot) config.when(options.hotEntries, c => { Object.keys(neutrino.options.mains).forEach(key => { c.entry(key).batch(entry => { options.hotEntries.forEach(hotEntry => entry.prepend(hotEntry)) entry .prepend(require.resolve('webpack/hot/dev-server')) .prepend(`${require.resolve('webpack-dev-server/client')}?/`) }) }) }) }) neutrino.use(devServer, options.devServer) neutrino.use(browserSync, { browserSyncOptions: { port: 4000, proxy: { target: 'http://localhost:3100/', ws: true }, logPrefix: 'Laima', open: true }, pluginOptions: { reload: false } }) }) .when(process.env.NODE_ENV === 'production', config => { config .plugin('vendor-chunk') .use(optimize.CommonsChunkPlugin, [ { name: 'vendor', minChunks: module => module.context && module.context.indexOf('node_modules') !== -1 } ]) .end() .plugin('runtime-chunk') .use(optimize.CommonsChunkPlugin, [ { name: 'runtime', minChunks: Infinity } ]) .end() .when(options.minify, () => neutrino.use(minify, options.minify)) .plugin('module-concat') .use(optimize.ModuleConcatenationPlugin) neutrino.use(pwa, { updateStrategy: 'changed', autoUpdate: true, ServiceWorker: { events: true, navigateFallbackURL: '/', minify: true } }) neutrino.use(compression) }) .when(neutrino.options.command === 'build', config => { config.when(options.clean, () => neutrino.use(clean, options.clean)) config.output.filename('[name].[chunkhash].js') }) }